package com.mf.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelAnalysisStopException;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.read.listener.ReadListener;
import com.mf.entity.ReadErrorModel;
import com.mf.entity.Test1Vo;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * Excel读取监听器，针对Test1Vo类型的数据显示和处理。
 * 使用者可以通过实现Consumer和Predicate接口来自定义数据处理逻辑和数据筛选条件。
 */
@Slf4j
public class EasyExcelTest1ReadListener implements ReadListener<Test1Vo> {
    /**
     * 批量处理的大小，当缓存数据达到该值时，将触发数据处理操作。
     */
    private final int bathSize;
    /**
     * 用于临时存储读取到的Test1Vo对象的缓存列表。
     */
    private final List<Test1Vo> cacheData;
    /**
     * 用于处理批量Test1Vo对象的消费者接口。
     */
    private final Consumer<List<Test1Vo>> consumer;
    /**
     * 用于筛选Test1Vo对象的条件谓词。
     */
    private final Predicate<Test1Vo> predicate;

    @Getter
    private ReadErrorModel readErrorModel;

    /**
     * 构造函数，初始化监听器。
     *
     * @param bathSize  批量处理大小
     * @param consumer  数据处理逻辑的消费者
     * @param predicate 数据筛选条件的谓词
     */
    public EasyExcelTest1ReadListener(int bathSize, Consumer<List<Test1Vo>> consumer, Predicate<Test1Vo> predicate) {
        this.bathSize = bathSize;
        this.cacheData = new ArrayList<>(this.bathSize);
        this.consumer = consumer;
        this.predicate = predicate;
    }

    /**
     * 构造函数，使用默认的批量处理大小初始化监听器。
     *
     * @param consumer  数据处理逻辑的消费者
     * @param predicate 数据筛选条件的谓词
     */
    public EasyExcelTest1ReadListener(Consumer<List<Test1Vo>> consumer, Predicate<Test1Vo> predicate) {
        this(2, consumer, predicate);
    }

    /**
     * 当读取到单条Test1Vo数据时调用该方法。
     *
     * @param test1Vo         读取到的单条数据
     * @param analysisContext 上下文信息，包含读取过程中的状态
     */
    @Override
    public void invoke(Test1Vo test1Vo, AnalysisContext analysisContext) {
        // 根据谓词筛选数据，不符合条件的不处理
        if (!this.predicate.test(test1Vo)) {
            return;
        }
        // 日志记录读取到的数据
        log.info("读取到一条数据：{}", test1Vo);

        // 将数据添加到缓存列表
        this.cacheData.add(test1Vo);
        // 当缓存数据达到批量处理大小时，处理缓存数据
        if (this.cacheData.size() >= this.bathSize) {
            this.consumer.accept(this.cacheData);
            this.cacheData.clear();
        }
    }

    /**
     * 所有数据读取完毕后调用该方法。
     *
     * @param analysisContext 上下文信息，包含读取过程中的状态
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 处理剩余的缓存数据
        if (!this.cacheData.isEmpty()) {
            this.consumer.accept(this.cacheData);
        }
    }

    /**
     * 处理数据读取过程中的异常情况。
     *
     * @param exception 异常对象
     * @param context   上下文信息，包含读取过程中的状态
     * @throws Exception 异常抛出，停止数据读取
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        System.out.println("=====================");
        // 异常转换，确保类型正确
        ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;
        // 获取异常相关的行号、列号、单元格数据和错误原因
        int rowIndex = excelDataConvertException.getRowIndex();
        int columnIndex = excelDataConvertException.getColumnIndex();
        String cellData = excelDataConvertException.getCellData().getStringValue();
        String reason = excelDataConvertException.getCellData().getStringValue();
        // 格式化错误信息
        String errorMessage = String.format("数据转换异常，行号：%d，列号：%d，数据：%s，原因：%s", rowIndex, columnIndex, cellData, reason);
        this.readErrorModel = new ReadErrorModel(cellData, errorMessage, rowIndex + 1, columnIndex + 1);
        // 抛出异常，停止数据读取
        throw new ExcelAnalysisStopException(errorMessage);
    }
}

